import {
  Graph,
  Node,
  Color,
  NODE_WIDTH,
  LINE_HEIGHT,
} from "@/components/x6antv";
import { Snapline } from "@antv/x6-plugin-snapline";
import { MiniMap } from "@antv/x6-plugin-minimap";
import { Scroller } from "@antv/x6-plugin-scroller";
import { History } from "@antv/x6-plugin-history";
import { Keyboard } from "@antv/x6-plugin-keyboard";
import { Clipboard } from "@antv/x6-plugin-clipboard";
import { Selection } from "@antv/x6-plugin-selection";
import { Transform } from "@antv/x6-plugin-transform";

const mkGraph = (
  container: HTMLDivElement,
  miniContainer: HTMLDivElement
): Graph => {
  const graph = new Graph({
    container: container,
    highlighting: {
      // 当连接桩可以被链接时，在连接桩外围渲染一个 2px 宽的红色矩形框
      // 连接桩吸附连线时在连接桩外围围渲染一个包围框
      magnetAdsorbed: {
        name: "stroke",
        args: {
          rx: 5,
          ry: 5,
          padding: 10,
          attrs: {
            stroke: "#31d0c6",
            strokeWidth: 4,
          },
        },
      },
    },
    interacting: function (cellView) {
      if (
        cellView.cell.getData() != undefined &&
        !cellView.cell.getData().disableMove
      ) {
        return { nodeMovable: false };
      }
      return true;
    },
    background: {
      color: "#F2F7FA",
    },
    connecting: {
      createEdge() {
        return this.createEdge({
          shape: "edge",
          attrs: {
            line: {
              sourceMarker: "path",
              targetMarker: "path",
              stroke: Color.random().toHex(),
            },
          },
        });
      },
      highlight: true,
      allowBlank: false,
      allowNode: false,
      allowPort(this, args) {
        const edges = this.getEdges();
        for (let i = 0; i < edges.length; i++) {
          const edge = edges[i];
          if (
            (edge.getSourceCellId() === args.sourceCell?.id &&
              edge.getSourcePortId() === args.sourcePort &&
              edge.getTargetCellId() === args.targetCell?.id &&
              edge.getTargetPortId() === args.targetPort) ||
            (edge.getSourceCellId() === args.targetCell?.id &&
              edge.getSourcePortId() === args.targetPort &&
              edge.getTargetCellId() === args.sourceCell?.id &&
              edge.getTargetPortId() === args.sourcePort)
          ) {
            return false;
          }
        }
        return true;
      },
      connectionPoint: {
        name: "boundary",
        args: {
          sticky: true,
          extrapolate: true,
        },
      },
      anchor: {
        name: "midSide",
        args: {
          direction: "H",
        },
      },
      router: {
        name: "metro",
        args: {
          padding: 20,
          startDirections: ["right", "left"],
          endDirections: ["right", "left"],
        },
      },
      connector: {
        name: "jumpover",
        args: {
          radius: 5,
          type: "cubic",
        },
      },
    },
    mousewheel: {
      enabled: true,
      modifiers: "Ctrl",
      maxScale: 4,
      minScale: 0.2,
    },
    grid: {
      visible: true,
      type: "doubleMesh",
      args: [
        {
          color: "#eee", // 主网格线颜色
          thickness: 1, // 主网格线宽度
        },
        {
          color: "#ddd", // 次网格线颜色
          thickness: 1, // 次网格线宽度
          factor: 4, // 主次网格线间隔
        },
      ],
    },
    translating: {
      restrict(view) {
        if (view) {
          const cell = view.cell;
          if (cell.isNode()) {
            const parent = cell.getParent();
            if (parent) {
              return parent.getBBox();
            }
          }
        }
        return null;
      },
    },
  });
  graph.use(
    new Snapline({
      enabled: true,
    })
  );

  graph.defineMarker({
    tagName: "circle",
  });

  graph.use(
    new Transform({
      resizing: {
        enabled: true,
        allowReverse: false,
        restrict: true,
        minWidth: NODE_WIDTH,
        maxWidth: NODE_WIDTH * 7,
        minHeight(node: Node) {
          const defHeight = node.size().height;
          if (defHeight) {
            return Number(defHeight);
          }
          return LINE_HEIGHT * 2;
        },
        maxHeight(node: Node) {
          const defHeight = node.size().height;
          if (defHeight) {
            return Number(defHeight);
          }
          return 0;
        },
      },
    })
  );
  graph.use(
    new Clipboard({
      enabled: true,
    })
  );
  graph.use(
    new Selection({
      enabled: true,
      multiple: true,
      rubberband: true,
      movable: true,
      showNodeSelectionBox: true,
    })
  );
  graph.setRubberbandModifiers("ctrl");
  graph.use(
    new Scroller({
      enabled: true,
      pageVisible: true,
      pageBreak: true,
      pannable: true,
      autoResize: true,
    })
  );
  graph.use(
    new History({
      enabled: true,
    })
  );
  graph.use(
    new Keyboard({
      enabled: true,
    })
  );
  graph.use(
    new MiniMap({
      container: miniContainer,
      width: 200,
      height: 160,
      padding: 10,
    })
  );

  graph.on("node:resizing", ({ node }) => {
    node.getPorts().forEach((port) => {
      if (port.id)
        node.portProp(port.id, "attrs/portBody/width", node.size().width);
    });
  });

  graph.bindKey("ctrl+c", () => {
    const cells = graph.getSelectedCells();
    if (cells.length) {
      graph.copy(cells);
    }
    return false;
  });

  graph.bindKey("ctrl+v", () => {
    if (!graph.isClipboardEmpty()) {
      const cells = graph.paste({ offset: 32 });
      graph.cleanSelection();
      graph.select(cells);
    }
    return false;
  });

  graph.bindKey("ctrl+z", () => {
    graph.undo();
  });

  return graph;
};

export { mkGraph };
